#ifndef GRILLA_H
#define GRILLA_H

#include <iostream>
#include "malloc.h"
#include "Imprimible.h"
#include "Casillero.h"
#include "Obstaculo.h"
#include "PositionOutOfBoundException.h"


using namespace std;

class Grilla : public Imprimible {

	private:
		int filas;
		int columnas;
		std::string tipoObstaculoPorDefecto;
		Casillero** casilleros;

		void initilize(int filas, int columnas, std::string obsDefecto){
			this->filas = filas;
			this->columnas = columnas;

			this->casilleros = (Casillero**)malloc(filas*sizeof(Casillero*));

			/* Optimizado abajo
			for(int i=0;i<filas; i++){
				this->casilleros[i] = (Casillero*)malloc(columnas*sizeof(Casillero));
			}*/

			this->tipoObstaculoPorDefecto = obsDefecto;

			for(int i=0;i<this->filas;i++){
				// Por cada fila reservo la memoria
				this->casilleros[i] = (Casillero*)malloc(columnas*sizeof(Casillero));

				for(int j=0;j<this->columnas;j++){
					this->casilleros[i][j].setPosicion(i,j);
					Casillero* casillero = &this->casilleros[i][j];
					Obstaculo* obs = new Obstaculo(i,j);
					obs->setTipo(this->tipoObstaculoPorDefecto);
					casillero->setContenido(obs);
					this->casilleros[i][j] = (*casillero);
				}
			}
		}

	public:

		Grilla(int filas, int columnas, std::string obsDefecto){
			this->initilize(filas,columnas,obsDefecto);

		}

		Grilla(int filas, int columnas){
			this->initilize(filas,columnas,"desconocido");
		}

		int getFilas(){
			
			return this->filas;
		}

		int getColumnas(){
		
			return this->columnas;
		}

		string getTipoObstaculoPorDefecto(){
			return this->tipoObstaculoPorDefecto;
		}

		Casillero* getCasillero(int fila, int columna){
			
			if(this->esPosicionInvalida(fila,columna)) {
				throw new PositionOutOfBoundException();
			} else {

				return &this->casilleros[fila][columna];
			}
			
		}

		void setCasillero(int fila, int columna, Casillero* casillero){
			
			if(this->esCasilleroInvalido(casillero)) {
				throw new PositionOutOfBoundException();
			} else {
				this->casilleros[fila][columna] = (*casillero);
			}
		}
	
		bool esCasilleroInvalido(Casillero* casillero){
		
			if( (casillero->getFila() < 0) || (casillero->getFila() >= this->filas) ){
			
				return true;
			}
			
			if( (casillero->getColumna()< 0) || (casillero->getColumna() >= this->columnas) ){

				return true;
			}
			return false;
		}

		bool esPosicionInvalida(int fila, int columna){
		
			if( (fila < 0) || (fila >= this->filas) ){

				return true;
			}

			if( (columna < 0) || (columna >= this->columnas) ){

				return true;
			}
			return false;
		}
		
		void Grilla::imprimir(){
			for(int i = 0; i < this->filas; i++){
				
				for(int j = 0; j < this->columnas; j++){
					
					Casillero *casillero = this->getCasillero(i,j);
					if(casillero){
						casillero->imprimir();
					}
				}
			}
//			Pantalla::getInstance()->refrescar();
		}

		void imprimir2(){
			
			for(int i = 0; i < this->filas; i++){
				
				for(int j = 0; j < this->columnas; j++){
					
					this->getCasillero(i,j)->imprimir2();
					
				}
				cout<<endl;
			}
		}

		~Grilla(){

			for(int i=0;i<this->filas;i++){
				for(int j=0;j<this->columnas;j++){
					delete this->casilleros[i][j].getContenido();
				}
			}

			for(int i=0;i<this->filas;i++){
				free(this->casilleros[i]);
			}
			free(this->casilleros);
		}
};
#endif 
